

#include "stdafx.h"
#include "../Lab1_Large_numbers/__uintX2.h"
#include "../Lab3_Primality_test/poklington_test.h"
using std::cout;
using std::endl;

int main(int argc, char* argv[])
{
	system("cls");
    cout << "Preparing...\n";
    // start the random counter
    srand(int(time(NULL)));

	if(argc != 2) 
	{
		cout<<"Set the size of the session key K";
		return 1;
	}

	size_t size = atoi(argv[1]);
	cout<<"The size of session key K is "<< size << endl;

	// get public group
	const uint128 p = poklington().get_prime(size);
	// ...and random numbers from [2 .. p - 2] that would be coprime with p - 1
	uint128 a, b;
	do
	{
		a = uint128::random() % (p - 3) + 2;
	}
	while(uint128::gcd(a, p - 1) != 1);
	do
	{
		b = uint128::random() % (p - 3) + 2;
	}
	while(uint128::gcd(b, p - 1) != 1);
	
	
	cout << "\tp = " << p << endl;


	// Alice choose random key from Zp* 
	const uint128 K = uint128::random() % p;
    cout << "\tA: K = " << K << endl;

	
	const uint128 x1 = uint128::pow_m(K, a, p);
    cout << "\tA -> B : x1 = K ^ a mod p = " << K << " ^ " << a << " mod " << p << " = " << x1 << endl;

	const uint128 x2 = uint128::pow_m(x1, b, p);
    cout << "\tB -> A : x2 = x1 ^ b mod p = " << x1 << " ^ " << b << " mod " << p << " = " << x2 << endl;

	const uint128 _a = a.inv(p-1);
	const uint128 x3 = uint128::pow_m(x2, _a, p);
    cout << "\tA -> B : x3 = x2 ^ -a mod p = " << x2 << " ^ " << _a << " mod " << p << " = " << x3 << endl;

	const uint128 _b = b.inv(p-1);
	const uint128 K_ = uint128::pow_m(x3, _b, p);
    cout << "\tB : K' = x3 ^ -b mod p = " << x3 << " ^ " << _b << " mod " << p << " = " << K_ << endl;

  
    // Check the key
	cout << "\tKey transfer " << ((K==K_)?("successfull"):("failed")) << endl;

	system("pause");
	return 0;
}

